#include "Classe.h"

#include "ATL.h"

#include "lib.h"

#include "Caracteristique.h"

#include "CodesErreurs.h"

#include <algorithm>

#include <functional>

#include <boost/lambda/lambda.hpp>

#include <boost/assign/list_of.hpp>

using namespace std;
using namespace boost::assign;
using namespace boost::lambda;

//const unsigned Classe::Zero( 0 );

const unsigned Classe::PasTrouve( 0xFFFF );

bool Classe::niveauxLus( false );

const vector< string > Classe::NomsNiveaux =
  list_of( "Classe::elementaire" )( "Classe::fonction" );

DebugLevelType Classe::elementaire  = INFO;
DebugLevelType Classe::fonction     = INFO;

/** Constructeur par défaut.
 * Ce constructeur ne devrait pas être appelé, mais pour être sûr, je
 * l'ai quand même implémenté.
 *
 * Il crée une Classe "fonctionnelle" dans le sens que n'importe
 * quelle méthode appelée sur une instance créée par ce moyen devrait
 * s'exécuter sans erreur.
 */
Classe::Classe()
  : ADDObjetBase( "Classe" ), PV( 1 ), XP( 1 ), NombrePPsAlloues( 0 ),
    NombreTotalCompetences( 0 ), NombreTotalRestrictions( 0 ), 
    NombreTotalEnsembles( 0 ), NombreMaxCompetences( 0 )
{
  //Traits.assign( 7, 0 );

  Niveau = 0;
  NiveauMagique = 0;
  TC.push_back(Toutes);

  if ( ! niveauxLus )
    {
      lireNiveaux( this, NomsNiveaux );
      niveauxLus = true;
    }
}

/**
 * Constructeur standard. Est utilisé lors de la création d'une Classe
 * en mode console ou graphique. Initialise les pointeurs et fixe les
 * traits et le TypeClasse. La liste des compétences accessibles est
 * également mise à jour.
 *
 * @param[in] xp Nombre de pt d'expérience du personnage
 * @param[in] tc type de classe (càd Combattant, Mage, Prêtre ou
 * Roublard) du personnage
 */
Classe::Classe(const unsigned& xp, const TypeClasse& tc,
	       const string& nomClasse )
  : ADDObjetBase( nomClasse ), PV( 1 ), XP( xp ), NomClasse( nomClasse ),
    NombrePPsAlloues( 0 ), NombreTotalCompetences( 0 ),
    NombreTotalRestrictions( 0 ), NombreTotalEnsembles( 0 ),
    NombreMaxCompetences( 0 )
{
  //Traits.assign( trait.begin(), trait.end() );

  Niveau = 0;
  NiveauMagique = 0;
  TC.push_back(Toutes);
  TC.push_back(tc);

  if ( ! niveauxLus )
    {
      lireNiveaux( this, NomsNiveaux );
      niveauxLus = true;
    }
}

/**
 * Constructeur de copie, réalise la copie profonde.
 *
 * @param[in] classe instance à copier
 */
Classe::Classe(const Classe& classe)
  : ADDObjetBase( classe.NomClasse ), PV( classe.PV ), XP( classe.XP ),
    NombrePPsAlloues( classe.NombrePPsAlloues ),
    NombreTotalCompetences( classe.NombreTotalCompetences ),
    NombreTotalRestrictions( classe.NombreTotalRestrictions ),
    NombreTotalEnsembles( classe.NombreTotalEnsembles ),
    NombreMaxCompetences( classe.NombreMaxCompetences )
{
  ListesCompetences.assign( classe.ListesCompetences.begin(),
			    classe.ListesCompetences.end() );
  ListeRestrictions.assign( classe.ListeRestrictions.begin(),
			    classe.ListeRestrictions.end() );
  EnsemblesCompetences.assign( classe.EnsemblesCompetences.begin(),
			       classe.EnsemblesCompetences.end() );
  PrerequisClasse.assign( classe.PrerequisClasse.begin(),
			  classe.PrerequisClasse.end() );
  RacesAdmisesClasse.assign( classe.RacesAdmisesClasse.begin(),
			     classe.RacesAdmisesClasse.end() );

  NomClasse     = classe.NomClasse;

  //Traits.assign( classe.Traits.begin(), classe.Traits.end() );
  Niveau = classe.Niveau;
  NiveauMagique = classe.NiveauMagique;
  Competences.assign( classe.Competences.begin(), classe.Competences.end() );
  TC.assign( classe.TC . begin(), classe.TC . end() );

  if ( ! niveauxLus )
    {
      lireNiveaux( this, NomsNiveaux );
      niveauxLus = true;
    }
}

/** Destructeur.
 *
 */
Classe::~Classe()
{}

/**
 * Sert à afficher le niveau du personnage (si le personnage est
 * multi-classé, affiche le niveau de la Classe).
 *
 * @param[in] os flot de sortie utilisé.
 */
void Classe::affiche( ostream& os ) const
{
  os << "Niveau : " << Niveau << endl;
}

/**
 * Sert à afficher le niveau du personnage (si le personnage est
 * multi-classé, affiche le niveau de la Classe).
 *
 * @param[in] flot instance de FlotMssage de sortie utilisée.
 */
void Classe::affiche( FlotMessage& flot ) const
{
  flot << "Niveau : " << Niveau << endmsg;
}


/**
 * Nouvelle méthode, qui s'occupe de déterminer\n 1) le niveau\n 2) le
 * niveau de magie\n 3) le TAC0.
 *
 * @return le TAC0
 */
unsigned Classe::calculeNombres()
{
  calculNiveau();
  calculNivMag();

  return calculeTAc0();
}

/**
 * Affiche un récapitulatif de la classe comprenant les traits, les
 * restrictions et les compétences. Fait appel à
 * afficheCompetences().
 *
 * Le niveau de sortie est paramétré par Classe::elementaire :\n
 * \e FUNC permet d'afficher le nom au début et à la fin de la
 * méthode.
 *
 * @param[in] os flot sur lequel les information seront écrites, par
 * défaut blank()
 */
void Classe::afficheStats( const string& nomRace,
			   const vector< unsigned >& traits,
			   ostream& os ) const
{
  empileNiveau( &elementaire );
  func() << "Classe::afficheStats -> début" << endmsg;

  os << "Classe : " << NomClasse << endmsg;

  afficheCompetences( nomRace, traits, os );

  func() << "Classe::afficheStats -> fin" << endmsg;
  depileNiveau();
}

/**
 * Affiche un récapitulatif de la classe comprenant les traits, les
 * restrictions et les compétences. Fait appel à
 * afficheCompetences().
 *
 * Le niveau de sortie est paramétré par Classe::elementaire :\n
 * \e FUNC permet d'afficher le nom au début et à la fin de la
 * méthode.
 *
 * @param[in] os flot sur lequel les information seront écrites, par
 * défaut blank()
 */
void Classe::afficheStats( const string& nomRace,
			   const vector< unsigned >& traits,
			   FlotMessage& flot ) const
{
  empileNiveau( &elementaire );
  func() << "Classe::afficheStats -> début" << endmsg;

  flot << "Classe : " << NomClasse << endmsg;

  afficheCompetences( nomRace, traits, flot );

  func() << "Classe::afficheStats -> fin" << endmsg;
  depileNiveau();
}

/**
 * Sert à déterminer les compétences de classe du personnage. Est
 * appelé lors de la lecture d'un fichier xml.
 *
 * @param[in] capa est le vecteur qui contient les compétences
 */
void Classe::setCompetences(const vector<unsigned>& capa)
{
  Competences.assign( capa . begin(), capa . end() );
}

// /**
//  * Sert à déterminer les traits du personnage.
//  */
// void Classe::setTraits(const vector< unsigned >& traits)
// {
//   Traits.assign( traits.begin(), traits.end() );
// }

/**
 * Affiche les compétences de classe.  Est destimé à faire un
 * récapitulatif des compétences de classe, lors de l'utilisation du
 * soft en mode console. Permet également de récupérer les information
 * pour un Aperçu du personnage (console ou graphique).
 *
 * Fait appel à competence(), pour pouvoir gérer de manière simple
 * les restrictions et les compétences associées à un pourcentage.
 *
 * Le niveau de sortie est paramétré par Classe::fonction :\n
 * \e FUNC permet d'afficher le nom au début et à la fin de la
 * méthode.\n
 * \e DEBUG permet d'afficher le nombre de compétences.
 *
 * @param[in] traits liste des traits du personnage.
 * @param[in] os flot, blank() est utilisé par défaut
 */
void Classe::afficheCompetences( const string& nomRace,
				 const vector< unsigned >& traits,
				 ostream& os ) const
{
  empileNiveau( &fonction );
  func() << "Classe::afficheCompetences -> début" << endmsg;
  
  os << "Récapitulation des compétences de classe : " << endmsg;
  unsigned taille( tailleCompetences() );
  string comp_str;
  bool pourcent( false );
  
  debug() << "Nbr de comp : " << taille << endmsg;
  
  for (unsigned i(0); i < taille; i++)
    {
      comp_str = nomCompetence( i, nomRace, traits, pourcent );
      os << comp_str << endmsg;
      if ( pourcent && i == taille - 2 )
	break;
      else if ( pourcent )
	i++;
    }
  
  func() << "Classe::afficheCompetences -> fin" << endmsg;
  depileNiveau();
}

/**
 * Affiche les compétences de classe.  Est destimé à faire un
 * récapitulatif des compétences de classe, lors de l'utilisation du
 * soft en mode console. Permet également de récupérer les information
 * pour un Aperçu du personnage (console ou graphique).
 *
 * Fait appel à competence(), pour pouvoir gérer de manière simple
 * les restrictions et les compétences associées à un pourcentage.
 *
 * Le niveau de sortie est paramétré par Classe::fonction :\n
 * \e FUNC permet d'afficher le nom au début et à la fin de la
 * méthode.\n
 * \e DEBUG permet d'afficher le nombre de compétences.
 *
 * @param[in] traits liste des traits du personnage.
 * @param[in] os flot, blank() est utilisé par défaut
 */
void Classe::afficheCompetences( const string& nomRace,
				 const vector< unsigned >& traits,
				 FlotMessage& flot ) const
{
  empileNiveau( &fonction );
  func() << "Classe::afficheCompetences -> début" << endmsg;
  
  flot << "Récapitulation des compétences de classe : " << endmsg;
  unsigned taille( tailleCompetences() );
  string comp_str;
  bool pourcent( false );
  
  debug() << "Nbr de comp : " << taille << endmsg;
  
  for (unsigned i(0); i < taille; i++)
    {
      comp_str = nomCompetence( i, nomRace, traits, pourcent );
      flot << comp_str << endmsg;
      if ( pourcent && i == taille - 2 )
	break;
      else if ( pourcent )
	i++;
    }
  
  func() << "Classe::afficheCompetences -> fin" << endmsg;
  depileNiveau();
}

/**
 * Permet de retrouver le nom de la Classe.
 *
 * @return le nom de la classe ("Guerrier", "Voleur", ...).
 */
const string& Classe::classe() const
{
  return NomClasse;
}

/**
 * Donne le nombre courant de pts de vie de la classe.
 *
 * @return nombre de pts de vie.
 */
const unsigned& Classe::pv() const
{
  return PV;
}

/**
 * Donne le nombre courant de pts d'expérience.
 *
 * @return nombre de pts d'expérience.
 */
const unsigned& Classe::xp() const
{
  return XP;
}

/// **
//  * Permet de changer la valeur d'un trait \e après la création de la
//  * classe.
//  *
//  * @param i numéro du trait
//  * @param val nouvelle valeur du trait
//  */
// void Classe::setTrait(const unsigned& i, const unsigned& val)
// {
//   if ( i < 7 )
//     Traits[ i ] = val;
// }

// /**
//  * Récupère le trait désiré (y compris le score de force expectionnel.
//  *
//  * @param i indice du trait voulu.
//  *
//  * @return la valeur du trait voulu (unsigned), ou PasTrouve en cas
//  * d'erreur.
//  */
// const unsigned& Classe::trait(const unsigned& i) const
// {
//   if (i < 7)
//     return Traits[i];
//   else
//     return PasTrouve;
// }

// /**
//  * Récupère un pointeur sur le conteneur des traits.
//  *
//  * @return pointeur sur Traits.
//  */
// const vector< unsigned >* Classe::traits() const
// {
//   return &Traits;
// }

/**
 * Donne le nombre de compétences.
 *
 * @return taille du conteneur Competences, si une (ou plusieurs)
 * compétence est associée à un pourcentage, ce nombre n'est pas le
 * nombre de compétences.
 */
unsigned Classe::tailleCompetences() const
{
  return Competences.size();
}

/**
 * Retourne le numero de la compétence dans la liste de toutes les
 * compétences de classe disponible.
 *
 * @param[in] i numéro de la compétence
 *
 * @return une référence constante sur Competences[i], ou sur l'entier
 * PasTrouve si l'indice dépasse la taille du conteneur.
 */
const unsigned& Classe::numCompetence(const unsigned& i) const
{
  if (i < Competences.size())
    return Competences[i];
  else
    return PasTrouve;
}


const string& Classe::nomCompetence( const unsigned& i,
				     const bool& LaTeX ) const
{
 const CompetenceClasse& tmp( competenceNumero( i ) );

 if ( tmp . nom() == "" )
   {
     warning() << "Compétence inexistante" << endmsg;
     return tmp . nom();
   }

 return LaTeX ? tmp . aliasNom() : tmp . nom();
}

/**
 * Permet de récupérer le nom de la compétence donnée, avec l'éventuel
 * pourcentage associé. Les scores évoluant avec le niveau tels que
 * l'\e Attaque \e sournoise du Voleur, \e Neutralisation du Rôdeur, etc, sont
 * également gérées ici.
 *
 * La méthode gère également les compétences bizarres, mais je ne suis
 * pas sûr qu'elle peut gérer comme il le faut le pourcentage associé
 * à un talent de Voleur prit comme compétence de Mage... il me semble
 * que oui.
 *
 * Le niveau de sortie est paramétré par Classe::fonction :\n
 * \e FUNC affiche le nom au début et à la fin de la méthode.\n
 * \e DEBUG affiche le numéro de la compétence.\n
 *
 * @param[in] i numéro de la compétence désirée.
 * @param[in] traits traits du personnage.
 * @param[out] sauter permet de savoir s'il faut sauter le prochain
 * nombre rencontré, lors de l'écriture des compétences
 * @param[in] LaTeX permet de (dés)activer le mode LaTeX pour
 * l'affichage des accents et du signe "%". Par défaut, la sortie est
 * en mode non LaTeX
 *
 * @return le nom de la compétence, suivi par le pourcentage si existant
 */
string Classe::nomCompetence( const unsigned& i,
			      const string& nomRace,
			      const vector< unsigned >& traits, bool& sauter,
			      const bool& LaTeX ) const
{
  /*Debug::*/empileNiveau( &fonction );
  func() << "Classe::nomCompetence -> début" << endmsg;
  
  const CompetenceClasse& tmp( competenceNumero( i ) );

  if ( tmp . nom() == "" )
    {
      warning() << "Compétence inexistante" << endmsg;
      return tmp . nom();
    }

  unsigned numComp( numCompetence( i ) );

  sauter = false;

  if ( tmp.pourcentage() )
    {
      func() << "Classe::competence -> fin" << endmsg;
      /*Debug::*/depileNiveau();
      sauter = true;
      if ( LaTeX )
	return tmp.aliasNom() + " " + ecrireString( numCompetence( i + 1 ) )
	  + " \\%";
      else 
	return tmp.nom() + ' '  + ecrireString( numCompetence( i + 1 ) ) + " %";
    }
  else if ( tmp.autreScore() == Basique )
    {
      func() << "Classe::nomCompetence -> fin" << endmsg;
      /*Debug::*/depileNiveau();
      if ( LaTeX )
	return tmp.aliasNom() + " " + scoreAdditionnel( numComp, nomRace,
						      traits );
      else
	return tmp.nom() + ' '  + scoreAdditionnel( numComp, nomRace, traits );
    }
  else if ( tmp.autreScore() == Pourcentage )
    {
      func() << "Classe::nomCompetence -> fin" << endmsg;
      /*Debug::*/depileNiveau();
      if ( LaTeX )
	return tmp.aliasNom() + " " + scoreAdditionnel( numComp, nomRace,
							traits )
	  + " \\%";
      else
	return tmp.nom() + ' '  + scoreAdditionnel( numComp, nomRace, traits )
	  + " %";
    }
  else
    {
      func() << "Classe::nomCompetence -> fin" << endmsg;
      /*Debug::*/depileNiveau();
      if ( LaTeX )
	return tmp.aliasNom();
      else
	return tmp.nom();
    }
}

/**
 * Permet de récupérer la valeur de base du pourcentage associé à une
 * compétence.
 *
 * On utilise competenceNumero, et on renvoie la valeur de ValeurBase,
 * car cette valeur est nulle si aucun pourcentage n'est associé à la
 * compétence.
 *
 * @param[in] i numéro de la compétence.
 *
 * @return valeur de base de la compétence.
 */
const unsigned & Classe::valeurBase(const unsigned& i) const
{
  const CompetenceClasse& tmp( competenceNumero( i ) );

  return tmp.valeurBase();
  // if ( ListesCompetences[ 0 ].at(i) . Pourcentage )
  //   return  ListesCompetences[ 0 ].at(i) . ValeurBase;
  // else
  //   return 0;
}

/**
 * Permet de récupérer le niveau du personnage (qui n'est pas accessible
 * depuis l'extérieur).
 *
 * @return niveau du personage (pour la classe considérée).
 */
const unsigned& Classe::niveau() const
{
  return Niveau;
}


/**
 * Permet de récupérer le niveau de magie du personnage (qui n'est pas
 * accessible depuis l'extérieur).
 *
 * @return niveau du personage (pour la classe considérée).
 */
const unsigned& Classe::niveauMagie() const
{
  return NiveauMagique;
}

/**
 * Réalise l'écriture du livre de sort dans la feuille de
 * personnage. Il s'agit ici du traitement générique, donc on ne fait
 * rien.
 *
 * Le niveau de sortie est paramétré par Classe::fonction :\n
 * \e FUNC affiche les messages de début et de fin de méthode.\n
 * \e DEBUG affiche le message "Rien à faire".
 *
 * @param[in] nom_fichier nom du fichier à éditer.
 * @param[in] ecrase permet d'ouvrir le fichier en écrasant le contenu
 * existant (\e true) ou en ajoutant les lignes après la dernière
 * ligne actuelle (\e false).
 * @param[in] sagesse valeur de la Sagesse du personnage (utilisé par
 * les Prêtres uniquement).
 */
void Classe::ecrireSorts( const string& nom_fichier, const bool& ecrase,
			  const unsigned& ) const
{
  /*Debug::*/empileNiveau( &fonction );
  func() << "Classe::ecrireSort -> début" << endmsg;

  debug() << "Rien à faire" << endmsg;
  ofstream sortie;
  if (ecrase)
    sortie.open(nom_fichier.c_str());
  else
    sortie.open(nom_fichier.c_str(), ios::app);
  sortie << "%"  << classe() << endl << "% rien à dire" << endl;
  sortie.close();

  func() << "Classe::ecrireSort -> fin" << endmsg;
  /*Debug::*/depileNiveau();
}

/**
 * Permet de récupérer le nombre de sort de chaque niveau que la
 * Classe peut lancer.
 *
 * Ici la méthode ne fait rien, la gestion est spécifique à la classe.
 *
 * Le niveau de sortie est paramétré par Classe::fonction :\n
 * \e FUNC affiche les messages de début et de fin de méthode.
 *
 * @param[out] sorts tableau contenant le nombre de sort de chaque
 * niveau disponibles, est édité par la méthode.
 */
void Classe::sortsParNiveau( vector< unsigned >& sorts,
			     const unsigned& ) const
{
  /*Debug::*/empileNiveau( &fonction );
  func() << "Classe::sortsParNiveau -> début" << endmsg;

  warning() << "Pas de sorts pour la classe " << classe() << endmsg;
  sorts.clear();
  
  func() << "Classe::sortsParNiveau -> fin" << endmsg;
}

/**
 * Sert à virer les accents dans le nom des écoles de magies et
 * sphères (écrit en syntaxe LaTeX pour plus de logique).
 *
 * Supprime en même temps le 2ème nom de l'école (càd Illusion -
 * Fantasme => Illusion).

 * Le niveau de sortie est paramétré par Classe::elementaire :\n
 * \e FUNC affiche le nom au début et à la fin de la méthode.\n
 * \e LFUNC permet d'afficher l'évolution de la chaîne de caractère
 * lors du traitement des accents.\n
 * \e DEBUG affiche l'évolution lors de la troncature.
 *
 * @todo Supprimer dés que possible et utilise AliasNom pour éviter
 * les éventuels problèmes d'accents pour des noms de dossiers /
 * fichiers.
 *
 * @param[in] brut string comprenant des accents en syntaxe Latex et /
 * ou des espaces.
 *
 * @return string sans accents ni espaces
*/
string Classe::supprimeAccents(const string& brut) const
{
  /*Debug::*/empileNiveau( &elementaire );
  func() << "Classe::supprimeAccents -> début" << endmsg;

  string retour(brut);
  size_t loc(retour.find("\\'", 0));
  while (loc != string::npos)
    {
      lfunc() << retour << ' ' << loc << endmsg;
      retour.replace(loc, 2, "");
      loc = retour.find("\\'", 0);
      lfunc() << retour << endmsg;
    }

  loc = retour.find("\\ -", 0);
  if (loc != string::npos)
    {
      // ici il faut tronquer le nom
      debug() << retour << " -> ";
      retour.replace(loc, retour.size() - loc, "");
      debug() << retour << endmsg;
    }

  loc = retour.find(" -", 0);
  if (loc != string::npos)
    {
      // ici il faut tronquer le nom
      debug() << retour << " -> ";
      retour.replace(loc, retour.size() - loc, "");
      debug() << retour << endmsg;
    }
    
  func() << "Classe::supprimeAccents -> fin" << endmsg;
  /*Debug::*/depileNiveau();
  return retour;
}

/**
 * Retourne le TypeClasse du personnage.
 *
 * @return TC, le type de classe du personnage.
 */
const vector<TypeClasse>* Classe::tc() const
{
  return &TC;
}

/**
 * Faire progresser le personnage, en augmentant son nombre de pts
 * d'expérience.
 *
 * @param[in] xp le nombre de pts d'expérience gagnés.
 */
void Classe::augmenterXP(const unsigned& xp)
{
  XP += xp;
  calculNiveau();
  calculNivMag();
}

/**
 * Permet d'augmenter le nombre de pts de vie du personnage.
 *
 * @param[in] pv le nombre de pts de vie gagnés.
 */
void Classe::augmenterPV(const unsigned& pv)
{
  PV += pv;
}

/**
 * Gestion des niveau de sortie des fonctions. Est appelée par
 * lireNiveauxSortie().
 *
 * @param[in] level le niveau (INFO, DEBUG, ...).
 * @param[in] n permet de sélectionner quel variable est affectée.
 */
void Classe::setLevel(const unsigned& level, const unsigned& n)
{
  switch(n)
    {
    case 1:
      elementaire = static_cast< DebugLevelType >( level );
      break;
    case 2:
      fonction = static_cast< DebugLevelType >( level );
      break;
    default:
      FlotMessage err( WARN, "Classe" );
      err << "Variable inconnue, dans Classe::setLevel " << n << endmsg;
    }
}

/**
 * Permet de remplir son Livre de sorts à partir des écoles
 * accessibles.  L'ajout est sécurisé (impossible de prendre deux fois
 * le sort).
 *
 * La méthode est spécifique à chaque classe ayant un livre de
 * sort. Cette méthode ne fait donc rien.
 *
 * Le niveau de sortie est paramétré par Classe::fonction :\n
 * \e FUNC affiche le message "rien à faire".
 */
void Classe::ajoutSorts()
{
  /*Debug::*/empileNiveau( &fonction );
  func() << "Classe::ajoutSorts : on est dans Classe, rien à faire ici"
	 << endmsg; 
  /*Debug::*/depileNiveau();
}

/**
 * Ajoute des sorts à la classe. On vérifie d'abord que la classe en
 * a, puis on ajoute les nouveaux et on trie le tout.
 *
 * Le niveau de sortie est paramétré par Classe::fonction :\n
 * \e FUNC permet d'afficher le nom au début et à la fin de la
 * méthode.\n
 * \e DEBUG affiche le nombre de sort qui seront ajoutés.
 *
 * @param[in] vec le conteneur des nouveaux sorts
 */
void Classe::ajoutSorts(const vector<Sort>& vec)
{
  /*Debug::*/empileNiveau( &fonction );
  func() << "Classe ajoutSorts -> début" << endmsg;

  if ( NiveauMagique > 0 )
    {
      debug() << vec.size() << " sort à ajouter" << endmsg;
      SortsClasse.insert(SortsClasse.end(), vec.begin(), vec.end());

      vector<Sort>::iterator Begin, End, it;
      Begin = SortsClasse.begin();
      End   = SortsClasse.end();

      sort(Begin, End);

      it = unique(Begin, End);

      SortsClasse.erase( it, End );
    }
  else
    debug() << "Rien à faire, niveau magique nul" << endmsg;
  
  func() << "Classe ajoutSorts -> fin" << endmsg;
  /*Debug::*/depileNiveau();
}

/**
 * Est utilisé lors de la lecture d'un personnage à partir d'un
 * fichier XML.  Elle permet de recréer le Livre de sorts du
 * personnage.
 *
 *  Le niveau de sortie est paramétré par Classe::elementaire :\n
 * \e FUNC affiche le nom au début et à la fin de la méthode.\n
 * \e DEBUG affiche le nombre de sort qui seront copiés.
 *
 * @param[in] sorts conteneur des sorts connus par le personnage.
 */
void Classe::setSorts(const vector<Sort>& sorts)
{
  /*Debug::*/empileNiveau( &elementaire );
  func() << "Classe setSorts -> début" << endmsg;

  debug() << "Nbr de sort à copier : " << sorts.size() << endmsg;

  SortsClasse.assign( sorts.begin(), sorts.end() );

  func() << "Classe setSorts -> fin" << endmsg;
  /*Debug::*/depileNiveau();
}

/**
 * Est utilisé pour fixer le nombre de pv lors de la création.
 *
 * @param[in] pv nombre de points de vie.
 */
void Classe::setPV(const unsigned& pv)
{
  PV = pv;
}

/**
 * Est utilisé pour fixer le nombre de xp juste après la création (si
 * le personnage n'est pas niveau 1 lors de la création)
 *
 * Le niveau ainsi que le niveau de magie du personnage sont
 * automatiquement mis à jour.
 *
 * @param[in] xp nombre de points d'expérience.
 */
void Classe::setXP(const unsigned& xp)
{
  XP = xp;

  calculNiveau();

  calculNivMag();
}

/**
 * Donne le nombre de sorts que le personnage connait.
 *
 * @return taille du containeur Cl_Sorts
 */
unsigned Classe::nbrSortsConnus() const
{
  if ( NiveauMagique > 0 )
    return this -> SortsClasse.size();
  else
    return 0;
}

/**
 * Applique les ajustements raciaux aux compétences de classe. Ne
 * touche que les talents de voleur et de barde.
 *
 * La méthode affiche un message d'erreur si elle est appelée pour un
 * Voleur ou un Barde.
 *
 * Le niveau de sortie est paramétré par Classe::elementaire :\n
 * \e FUNC affiche les messages de début et de fin de méthode.
 */
void Classe::appliquerModif( const string&, const unsigned&  )
{
  /*Debug::*/empileNiveau( &elementaire );
  func() << "Classe::appliquerModif -> début" << endmsg;

  if ( NomClasse == "Barde" || NomClasse == "Voleur" )
    warning() << NomClasse << " a sa propre méthode, ici on ne fait rien!"
	      << endmsg;

  func() << "Classe::appliquerModif -> fin" << endmsg;
  /*Debug::*/depileNiveau();
}

/**
 * Permet d'augmenter les talent associés à un pourcentage (Voleurs,
 * Bardes). Ne fait rien dans la cas générique.
 *
 * Le niveau de sortie est paramétré par Classe::elementaire :\n
 * \e FUNC affiche les messages de début et de fin de méthode.\n
 * \e INFO affiche un message de félicitations en cas de passage de
 * niveau.
 *
 * @param[in] lvl_up \e true lors d'un passage de niveau (valeur par
 * défaut), \e false est utilisé lors de la création du personnage.
 */
void Classe::augmenterTalents( const string&,
			       const vector< unsigned >&,
			       const bool& lvl_up )
{
  /*Debug::*/empileNiveau( &elementaire );
  func() << "Classe::augmenterTalent< -> début" << endmsg;

  if ( lvl_up )
    info() << "Félicitation pour le niveau gagné" << endmsg;

  func() << "Classe::augmenterTalents -> fin" << endmsg;
  /*Debug::*/depileNiveau();
}

/**
 * Permet de récupérer le conteneur des sorts de la classe (pour
 * magiciens et bardes uniquement).
 *
 * @return un pointeur sur le conteneur (const vector<Sort>*).
 */
const vector<Sort>* Classe::adresseSorts() const
{
  return const_cast<const vector<Sort>*>( &(this -> SortsClasse) );
}

/**
 * Permet de récupérer les compétences et restrictions de la classe,
 * ainsi que leurs nombres respectifs.
 *
 * Est utilisé dans construitClasse, ainsi que dans la classe
 * ConstruitClasse de l'interface graphique.
 *
 * @param[out] nbrComp nombre de compétences (écrit par la méthode).
 * @param[out] comp conteneur des compétences (écrit par la méthode).
 * @param[out] nbrRes nombre de restrictions (écrit par la méthode).
 * @param[out] restric conteneur des restrictions (écrit par la
 * méthode).
 */
void Classe::copieCompetencesClasse(unsigned& nbrComp,
				    vector<CompetenceClasse>& comp,
				    unsigned& nbrRes,
				    vector<CompetenceClasse>& restric) const
{
  nbrComp = NombreTotalCompetences;
  nbrRes  = NombreTotalRestrictions;

  comp.assign( ListesCompetences[ 0 ].begin(), ListesCompetences[ 0 ].end());

  if ( NombreTotalRestrictions != 0 )
    restric.assign( ListeRestrictions.begin(), ListeRestrictions.end());
  else
    restric.clear();
}

/**
 * Permet de récupérer un pointeur sur le conteneur des
 * compétences. La version par défaut renvoie les compétences de
 * classe. L'argument permet de récupérer les ensembles "tiroirs".
 *
 * @param[in] num indice de la liste voulue dans ListesCompetences.
 *
 * @return un pointeur sur \c ListesCompetences[num]
 */
const vector< CompetenceClasse >* Classe::listesCompetences(const unsigned& num) const
{
  if ( num >= ListesCompetences.size() )
    {
      warning() << "Tentative d'accéder à une liste de compétences inexistante"
		<< endmsg;
      return 0;
    }
  else
    return &ListesCompetences[ num ];
}

/**
 * Permet de récupérer le nombre d'ensembles de capacités raciales,
 * ainsi que le nombre maximal de ces capacités raciales. Sert pour
 * les spécialistes, avec une possible extension au Clercs, Druides.
 *
 * @param[out] nbr nombre d'ensembles différents.
 * @param[out] max nombre maximal de capacités dans un ensemble.
 */
void Classe::donneesEnsCompetences(unsigned& nbr, unsigned& max) const
{
  nbr = NombreTotalEnsembles;
  max = NombreMaxCompetences;
}

/**
 * Permet de récupérer la liste complète des ensembles de compétences,
 * avec leur coût respectif.
 *
 * @return un pointeur sur le conteneur des ensembles, ou un pointeur
 * nul s'il n'existe pas de tels ensembles.
 */
const vector< EnsembleCompetencesClasse >* Classe::ensembles() const
{
  return &EnsemblesCompetences;
}

/**
 * Retourne le sort désiré. En cas d'erreur, le sort retourné n'existe
 * pas (niveau 0 inexistant).
 *
 * @param[in] i numéro du sort
 *
 * @return le sort numéro i
 */
const Sort & Classe::sortNum(const unsigned& i) const
{
  if ( i < nbrSortsConnus() )
    return SortsClasse[i];

  return SortInconnu;
}

/**
 * Permet de savoir combien de PP sont alloués lors de la création
 * d'une classe donnée.
 *
 * @return le nombre de PP alloués.
 */
const unsigned& Classe::pp() const
{
  return NombrePPsAlloues;
}

/**
 * Retrouve les compétences et restrictions de la classe. Les numéros
 * de ces compétences sont retournées.
 *
 * @param nbr[out] nombre de compétences possédées.
 *
 * @return pointeur sur le conteneur des compétences possédées.
 */
const vector<unsigned>* Classe::competences(unsigned& nbr)
  const
{
  nbr = tailleCompetences();

  return &Competences;
}

/**
 * Retourne la compétences désirée. Si le numéro de compétence demandé
 * n'existe pas, on renvoie une compétence vide.
 *
 * @param[in] i numéro de la compétence désirée.
 *
 * @return compétence voulue.
 */
const CompetenceClasse & Classe::competenceNumero(const unsigned& i) const
{
  /*Debug::*/empileNiveau( &elementaire );
  func() << "Classe::competenceNumero -> début" << endmsg;

  debug() << "On recherche le numéro " << i << endmsg;

  unsigned numComp( Competences[i] );

  if ( numComp < NombreTotalCompetences )
    {
      debug() << " => Compétence classique" << endmsg;

      func() << "Classe::competenceNumero -> fin" << endmsg;
      /*Debug::*/depileNiveau();
      return  ListesCompetences[ 0 ].at( numComp ) ;
    }
  else if ( numComp >= NombreTotalCompetences &&
	    numComp < NombreTotalRestrictions + NombreTotalCompetences )
    {
      debug() << " => Restriction" << endmsg;

      func() << "Classe::competenceNumero -> fin" << endmsg;
      /*Debug::*/depileNiveau();
      return ListeRestrictions.at( numComp - NombreTotalCompetences );
    }
  else
    {
      debug() << " => Compétence \"à tiroir\"" << endmsg;
      /*
       * On va chercher à quel "ensemble" cette compétence appartient,
       * et comme ça on aura :
       * 1) le pointeur sur le conteneur
       * 2) l'index de la compétence dans ce conteneur.
       */
      CompetenceClasse tmp;
      unsigned j;
      unsigned aBase( 0 );
      for ( j = i - 1; j > 0; j-- )
	{
	  tmp = ListesCompetences[0].at( Competences[ j ] );
	  if ( ! tmp . sousCategorieDefinie() ) continue;
	  aBase = tmp . adresseBase();
	  /*
	   * La division entière sert à vérifier que le numéro de la
	   * compétence est bien égal à la valeur de vbase plus un
	   * petit nombre. Pour éviter le cas où \f$ 302 / 200 = 1 \f$
	   * on vérifie encore que le numéro de la compétence est dans
	   * le bon intervalle.
	   */
	  if ( numComp / aBase == 1 && ( numComp - aBase ) < 100 ) 
	    {
	      func() << "Classe::competenceNumero -> fin" << endmsg;
	      /*Debug::*/depileNiveau();
	      return ListesCompetences[ tmp.sousCategorie() ] . at( numComp - aBase );
	    }
	}
    }

  func() << "Classe::competenceNumero -> fin" << endmsg;
  /*Debug::*/depileNiveau();
  return competenceClasseInconnue();
}

/**
 * Permet de savoir si la classe possède des compétences associées à
 * un pourcentage.
 *
 * @return \e true si oui, \e false sinon. 
 */
bool Classe::possedePourcent() const
{
  /*Debug::*/empileNiveau( &fonction );
  func() << "Classe::possedePourcent -> début" << endmsg;

  unsigned taille( tailleCompetences() ), numero;

  for (unsigned i(0); i < taille; i++)
    {
      numero = numCompetence( i );
      debug() << "Courante : " << numero << endmsg;
      if ( numero >= NombreTotalCompetences ) continue;
      if ( ListesCompetences[ 0 ].at( numero ) . pourcentage() )
	{
	  func() << "Classe::possedePourcent -> fin" << endmsg;
	  /*Debug::*/depileNiveau();
	  return true;
	}
    }

  func() << "Classe::possedePourcent -> fin" << endmsg;
  /*Debug::*/depileNiveau();
  return false;
}

/**
 * Donne le nombre de point à dépenser pour l'amélioration des
 * compétences associées à un pourcentage. Sert pour la création et le
 * passage de niveau.
 *
 * @param[in] lvlUp doit être \e true si l'on est en train de passer
 * un niveau (valeur par défaut) et \e false lors de la création.
 *
 * @return le nombre de points à dépenser.
 */
unsigned Classe::pourcent(const bool& lvlUp) const
{
  if ( lvlUp )
    info() << "Félicitation pour le niveau gagné!" << endmsg;
  return 0;
}

/**
 * Permet de savoir si la classe a un score de Force
 * Exceptionnelle. Les Combattants ont un tel score naturellement, les
 * Clercs peuvent en avoir un à condition de prendre la capacité ad
 * hoc.
 *
 * @return \e true si oui, \e false sinon.
 */
bool Classe::forceExceptionnelle( const unsigned& force ) const
{
  if ( force == 18 && ( classe() == "Guerrier" || classe() == "Paladin"
			|| classe() == "Rôdeur" ) )
    return true;
  else
    return false;
}

/**
 * Permet de récupérer le score associé à une compétence, lorsque
 * celui-ci dépend uniquement du niveau (et / ou d'un trait). Pour une
 * Classe générique, il n'existe pas de telles compétences, donc rien
 * n'est fait ici.
 *
 * @param i[in] numéro de la compétence
 *
 * @return la chaîne de caractères correspondante, ici toujours "".
 */
string Classe::scoreAdditionnel( const unsigned& i,
				 const string&,
				 const vector< unsigned >& ) const
{
  /*Debug::*/empileNiveau( &fonction );
  func() << "Classe::scoreAdditionnel -> début" << endmsg;

  warning() << "Pas de score additionnel pour " << classe() << endmsg;

  if ( i > NombreTotalCompetences )
    warning() << "Et en plus cette compétence n'existe pas" << endmsg;

  func() << "Classe::scoreAdditionnel -> fin" << endmsg;
  /*Debug::*/depileNiveau();

  return "";
}

/**
 * Fait le boulot des anciens constructeurs des différentes classes :
 * permet la construction de la Classe de A à Z, on choisit les
 * restrictions et les compétences. Seul le spécialiste a un
 * traitement spécial, vu que l'on peut ôter des compétences (écoles
 * en opposition) déjà prises.
 *
 * @param[in,out] pps nombre de PP, qui est réutilisé dans la suite de
 * la séquence.
 * @param[in] traits traits du personnage.
 * @param[in] nomRace race du personnage.
 */
void Classe::construitClasse( unsigned& pps, const vector< unsigned >& traits,
			      const string& nomRace )
{
  /*Debug::*/empileNiveau( &elementaire );
  func() << "Classe::construitClasse -> début" << endmsg;
  unsigned nbrEns, nbrCapaEns, i, choix, confirmation( 2 ), savePP(pps),
    nbrElements;
  vector< unsigned > tmpComp, tmpRes;
  const vector< unsigned > *liste = 0;
  EnsembleCompetencesClasse ensemble;
  CompetenceClasse tmp;

  StatusCode sc;

  /*
   * D'abord on regarde si il y a un ensemble de compétences
   * raciales. Ces ensembles permettent de gérer les différents type
   * de Spécialistes par exemple.
   */
  donneesEnsCompetences(nbrEns, nbrCapaEns);

  if ( nbrEns  > 0 )
    {
      /*
       * Alors, on a bel et bien des ensembles de compétences. On
       * commence par les afficher toutes.
       */
      blank() << "Sélectionner l'ensemble de compétence de classe :" << endmsg;
      for (i = 0; i < nbrEns; i++)
	{
	  ensemble = ensembles() -> at( i );
	  if ( ensemble.prix() == 0)
	    blank() << i + 1 << ' ' << ensemble.nom() << endmsg;
	  else
	    blank() << i + 1 << ' ' << ensemble.nom()
		    << " (pour " << ensemble.prix() << " pp)" << endmsg;
	}
      if ( ! ensemble.choixPrealable() )
	{
	  blank() << ++i << " Aucun" << endmsg;
	  nbrEns++;
	}
      do
	{
	  choix = demanderUnsignedBorne( "(" + ecrireString( pps ) +
					 " pp) Choix : ", 1, nbrEns );
	  if ( pps < ensemble.prix() )
	    {
	      warning() << "Pas assez de pp" << endmsg;
	      choix = i;
	    }
	  else
	    {
	      linfo() << "On va vérifier le prérequis pour l'ensemble n° "
		      << choix - 1 /*ensembles() -> at( choix - 1 ) . numeroPrerequis()*/ << endmsg;
	      sc = prerequisOK( nomRace, traits, choix - 1 /*ensembles() -> at( choix - 1 ) . numeroPrerequis()*/ );
	      if ( ! sc )
		{
		  sc.afficher();
		  confirmation = 2;
		}
	      else
		{
		  pps -= ensemble.prix();
		  blank() << "Ensemble sélectionné : "
			  << ensembles() -> at( choix - 1 ) . nom()
			  << endmsg;
		  
		  confirmation =
		    demanderUnsignedBorne( "Entrer 1 pour confirmer, 2 pour annuler : ", 1, 2 );
		}
	    }
	}
      while ( confirmation == 2 );

      liste = ensembles() -> at( choix - 1 ) . membres();
      if ( liste != 0 )
	{
	  tmpComp.resize( liste -> size() );
	  transform( liste -> begin(), liste -> end(), tmpComp.begin(),
		     bind2nd( minus< unsigned >(), 1 ) );
	}
    }

  Competences.assign( tmpComp.begin(), tmpComp.end() );

  info() << NombreTotalCompetences << " compétences et "
	 << NombreTotalRestrictions << " restrictions" << endmsg;

  /*
   * Ici on s'occupe des éventuelles restrictions de la classe
   */
  if ( NombreTotalRestrictions > 0 )
    {
      savePP = pps;
      blank() << "Sélectionner les restrictions choisies :" << endmsg;
      for (i = 0; i < NombreTotalRestrictions; i++)
	{
	  blank() << i + 1 << ' ' << (ListeRestrictions.at( i )) . nom()
		  << " (pour " << (ListeRestrictions.at( i )) . prix() << " pp)"
		  << endmsg;
	}
      blank() << NombreTotalRestrictions + 1 << " Aucune" << endmsg;

      do
	{
	  pps = savePP;
	  tmpRes.clear();
	  do
	    {
	      choix = demanderUnsignedBorne( "(" + ecrireString( pps ) +
					     " pp) Choix : ",
					     1, NombreTotalRestrictions + 1 );
	      if ( choix != NombreTotalRestrictions + 1 )
		{
		  blank() << "Restriction sélectionnée : "
			  << ListeRestrictions.at( choix - 1 ) . nom()
			  << endmsg;
		  tmpRes.push_back( NombreTotalCompetences + choix - 1 );
		  pps += (ListeRestrictions.at( choix - 1 )) . prix();
		}
	    }
	  while ( choix != NombreTotalRestrictions + 1 );
	  nbrElements = tmpRes.size();
	  if ( nbrElements == 0 )
	    blank() << endmsg << "Aucune restriction sélectionée" << endmsg;
	  else
	    {
	      blank () << "Récapitulation des restrictions :" << endmsg;
	      for (i = 0; i < nbrElements; i++)
		blank() << ListeRestrictions.at( tmpRes[ i ] - NombreTotalCompetences ) . nom()
			<< endmsg;
	      blank() << endmsg;
	    }
	  confirmation = demanderUnsignedBorne( "Entrer 1 pour confirmer, 2 pour annuler : ", 1, 2 );
	}
      while ( confirmation == 2 );

      Competences.assign( tmpComp.begin(), tmpComp.end() );
    }

  // On passe aux compétences
  savePP = pps;
  blank() << "Séléctionner les compétences choisies :" << endmsg;
  for (i = 0; i < NombreTotalCompetences; i++)
    {
      blank() << i + 1 << ' ' << (ListesCompetences[ 0 ].at( i )) . nom()
	      << " (pour " << (ListesCompetences[ 0 ].at( i )) . prix() << " pp)"
	      << endmsg;
    }
  blank() << NombreTotalCompetences + 1 << " Aucune" << endmsg;
  
  do
    {
      pps = savePP;
      tmpComp.clear();
      do
	{
	  choix = demanderUnsignedBorne( "(" + ecrireString( pps ) +
					 " pp) Choix : ", 1, NombreTotalCompetences + 1 );
	  if ( choix != NombreTotalCompetences + 1 )
	    {
	      if ( pps >= (ListesCompetences[ 0 ].at( choix - 1 )) . prix() )
		{
		  blank() << "Compétence sélectionnée : "
			  << ListesCompetences[ 0 ].at( choix - 1 ) . nom()
			  << endmsg;
		  tmpComp.push_back( choix - 1 );
		  if ( ListesCompetences[ 0 ].at( choix - 1 ) . pourcentage() )
		    tmpComp.push_back( ListesCompetences[ 0 ].at( choix - 1 ).valeurBase() );
		  pps -= (ListesCompetences[ 0 ].at( choix - 1 )) . prix();
		}
	      else
		warning() << "Pas assez de pp" << endmsg;
	    }
	}
      while ( choix != NombreTotalCompetences + 1 );
      nbrElements = tmpComp.size();
      if ( nbrElements == 0 )
	blank() << endmsg << "Aucune compétence sélectionée" << endmsg;
      else
	{
	  blank () << "Récapitulation des Compétences :" << endmsg;
	  for (i = 0; i < nbrElements; i++)
	    {
	      tmp = ListesCompetences[ 0 ].at( tmpComp[i] );
	      blank() << tmp. nom();
	      if ( tmp. pourcentage() )
		{
		  blank() << ' ' << tmp . valeurBase() << " %";
		  i++;
		}
	      blank()<< endmsg;
	    }
	  blank() << endmsg;
	}
      confirmation = demanderUnsignedBorne( "Entrer 1 pour confirmer, 2 pour annuler : ", 1, 2 );
    }
  while ( confirmation == 2 );

  Competences.insert( Competences.end(), tmpComp.begin(), tmpComp.end() );
  Competences.insert( Competences.end(), tmpRes.begin(), tmpRes.end() );

  EcrireElementConteneur< unsigned, FlotMessage > ecrireUInt( &debug() );
  for_each( Competences.begin(), Competences.end(), ecrireUInt );
  debug() << endmsg;

  // Il faut encore ajouter la détermination des scores à pourcentage
  if ( possedePourcent() )
    augmenterTalents( nomRace, traits, false );
  
  func() << "Classe::construitClasse -> fin" << endmsg;
  /*Debug::*/depileNiveau();
}

/**
 * Donne accès au nombre d'ensembles de compétences.
 *
 * @return l'adresse de NombreTotalEnsembles.
 */
const unsigned* Classe::nbrEns() const
{
  return &NombreTotalEnsembles;
}

/**
 * Donne accès au nombre maximal de compétences dans un ensemble.
 *
 * @return l'adresse de NombreMaxCompetences.
 */
const unsigned* Classe::maxEns() const
{
  return &NombreMaxCompetences;
}

/**
 * Vérifie que l'on peut bien construire la Classe voulue. On vérifie
 * que les traits remplissent les prérequis et on vérifie également
 * que la race est compatible.
 *
 * @param[in] race nom de la Race (càd Elfe, Demi-Ogre, ...).
 * @param[in] traits traits du personnage.
 * @param[in] ensemble numéro de l'ensemble racial désiré (est en fait
 * utile pour les Spécialistes uniquement).
 *
 * @return StatusCode, \e true si tout est OK, \e false sinon. Le
 * message contient une brève explication.
 */
StatusCode Classe::prerequisOK(const string& race,
			       const vector< unsigned >& traits,
			       const unsigned& ensemble)
{
  /*Debug::*/empileNiveau( &elementaire );
  func() << "Classe::prerequisOK -> début" << endmsg;

  StatusCode sc;
  
  unsigned numRace( 0 ), numPrerequis( 0 );

  if ( ensembles() -> size() > 0 )
    {
      numRace      = ensembles() -> at( ensemble ).numeroRacesAdmises();
      numPrerequis = ensembles() -> at( ensemble ).numeroPrerequis();

      debug() << "Pour l'ensemble n° " << ensemble
	      << ", le n° des races admises est "
	      << numRace << " et celui des prérequis est le "
	      << numPrerequis << endmsg;

      debug() << "Vérifions si la race est OK" << endmsg;

      if ( RacesAdmisesClasse.size() <= numRace )
	{
	  error() << "Demande pour un ensemble inexistant" << endmsg;
	  
	  func() << "Classe::prerequisOK -> fin" << endmsg;
	  /*Debug::*/depileNiveau();
	  
	  return StatusCode( false, 0, CodesErreurs::DepassementPorteeAutre,
			     "Demande de l'ensemble " +
			     ecrireString( numRace ) + " sur "
			     + ecrireString( RacesAdmisesClasse.size() )  );
	}
      else if ( RacesAdmisesClasse[ numRace ] . find( race ) ==
		RacesAdmisesClasse[ numRace ] . end() )
	{
	  // Alors on n'a pas le droit!
	  error() << "Un " << race << " ne peut pas être " << NomClasse << endmsg;
	  
	  func() << "Classe::prerequisOK -> fin" << endmsg;
	  /*Debug::*/depileNiveau();
	  
	  return StatusCode( false, 0, 350,
			     race + " interdit pour " + NomClasse );
	}
    }
  else
    {
      debug() << "Aucun ensemble de compétences" << endmsg;

      if ( RacesAdmisesClasse[ numRace ] . find( race ) ==
	   RacesAdmisesClasse[ numRace ] . end() )
	{
	  error() << "Un " << race << " ne peut pas être " << NomClasse << endmsg;
	  
	  func() << "Classe::prerequisOK -> fin" << endmsg;
	  /*Debug::*/depileNiveau();
	  
	  return StatusCode( false, 0, 350,
			     race + " interdit pour " + NomClasse );
	}
    }

  if ( ensemble == -1u )
    {
      debug() << "Aucun ensemble racial spécifié" << endmsg;
      // S'il n'existe pas d'ensembles, alors rien à faire de spécial
      if ( NombreTotalEnsembles > 0 )
	{
	  unsigned i( 0 );
	  vector< Prerequis >::const_iterator it, Begin,
	    End;
	  do
	    {
	      Begin = PrerequisClasse[ i ] .begin();
	      End   = PrerequisClasse[ i ] .end();
	      for (it = Begin; it != End; it++)
		sc = it -> estOK( traits );
	    }
	  while( ! sc && i != NombreTotalEnsembles );
	  if ( ! sc )
	    return StatusCode( false, 0, 320, "Aucun ensemble accessible" );
	  else
	    return sc;
	}
      numPrerequis = 0;
    }

  if ( PrerequisClasse.size() > numPrerequis )
    {
      debug() << "Vérifions si les prérequis sont remplis" << endmsg;
      vector< Prerequis >::const_iterator it,
	Begin( PrerequisClasse[ numPrerequis ] . begin() ),
	End( PrerequisClasse[ numPrerequis ] . end() );
      
      Caracteristique caracteristique;

      for (it = Begin; it != End; it++)
	{
	  linfo() << "Vérification du prérequis n° " << numPrerequis
		  << ", qui est " << *it << endmsg;
	  sc = it -> estOK( traits );
	  if ( ! sc )
	    {
	      caracteristique.setValeur( sc.valeur() );
	      error() << caracteristique
		      << " doit être au minimum "
		      << sc.valeur( 1 ) << ", valeur courante : "
		      << traits[ caracteristique ]
		      << endmsg;

	      func() << "Classe::prerequisOK -> fin" << endmsg;
	      /*Debug::*/depileNiveau();
	      return sc;
	    }
	}
    }

  func() << "Classe::prerequisOK -> fin" << endmsg;
  /*Debug::*/depileNiveau();
  return sc;
}
